package io.xjar;

import io.xjar.jar.XJarClassLoader;
import io.xjar.key.XKey;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 插件管理器，用于动态加载和管理插件
 *
 * @author Payne 646742615@qq.com
 */
public class XPluginManager {
    private final Map<String, Plugin> plugins = new ConcurrentHashMap<>();
    private final File pluginDirectory;
    private final ClassLoader parentClassLoader;
    private final XDecryptor xDecryptor;
    private final XEncryptor xEncryptor;
    private final XKey xKey;

    public XPluginManager(String pluginDirectory, 
                          ClassLoader parentClassLoader,
                          XDecryptor xDecryptor,
                          XEncryptor xEncryptor,
                          XKey xKey) {
        this(new File(pluginDirectory), parentClassLoader, xDecryptor, xEncryptor, xKey);
    }

    public XPluginManager(File pluginDirectory,
                          ClassLoader parentClassLoader,
                          XDecryptor xDecryptor,
                          XEncryptor xEncryptor,
                          XKey xKey) {
        this.pluginDirectory = pluginDirectory;
        this.parentClassLoader = parentClassLoader;
        this.xDecryptor = xDecryptor;
        this.xEncryptor = xEncryptor;
        this.xKey = xKey;
        
        // 确保插件目录存在
        if (!this.pluginDirectory.exists()) {
            this.pluginDirectory.mkdirs();
        }
    }

    /**
     * 扫描并加载插件目录中的所有插件
     *
     * @throws IOException IO异常
     */
    public void loadPlugins() throws Exception {
        if (!pluginDirectory.exists() || !pluginDirectory.isDirectory()) {
            return;
        }

        // 遍历插件目录中的所有jar文件和.x文件
        Files.walkFileTree(pluginDirectory.toPath(), new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                String fileName = file.toString();
                if (fileName.endsWith(".jar") || fileName.endsWith(".x")) {
                    try {
                        loadPlugin(file.toFile());
                    } catch (Exception e) {
                        System.err.println("Failed to load plugin: " + file + ", error: " + e.getMessage());
                    }
                }
                return FileVisitResult.CONTINUE;
            }
        });
    }

    /**
     * 加载单个插件JAR文件
     *
     * @param jarFile 插件JAR文件
     * @throws Exception 加载异常
     */
    public void loadPlugin(File jarFile) throws Exception {
        String pluginName = getPluginName(jarFile);
        if (plugins.containsKey(pluginName)) {
            // 如果插件已经加载，先卸载
            unloadPlugin(pluginName);
        }

        // 创建插件类加载器
        URL jarUrl = jarFile.toURI().toURL();
        URL[] urls = new URL[]{jarUrl};
        
        // 使用XJarClassLoader来支持加密的插件JAR
        XJarClassLoader pluginClassLoader = new XJarClassLoader(
                urls, parentClassLoader, xDecryptor, xEncryptor, xKey);

        Plugin plugin = new Plugin(pluginName, jarFile, pluginClassLoader);
        plugins.put(pluginName, plugin);
        
        System.out.println("Loaded plugin: " + pluginName);
    }

    /**
     * 卸载插件
     *
     * @param pluginName 插件名称
     */
    public void unloadPlugin(String pluginName) {
        Plugin plugin = plugins.remove(pluginName);
        if (plugin != null) {
            try {
                // 关闭类加载器（如果有需要的话）
                if (plugin.getClassLoader() instanceof XJarClassLoader) {
                    // XJarClassLoader没有特殊的清理需求
                }
                System.out.println("Unloaded plugin: " + pluginName);
            } catch (Exception e) {
                System.err.println("Failed to unload plugin: " + pluginName + ", error: " + e.getMessage());
            }
        }
    }

    /**
     * 获取插件名称（基于JAR文件名）
     *
     * @param jarFile JAR文件
     * @return 插件名称
     */
    private String getPluginName(File jarFile) {
        String name = jarFile.getName();
        if (name.endsWith(".jar")) {
            return name.substring(0, name.length() - 4); // 移除.jar后缀
        }
        if (name.endsWith(".x")) {
            return name.substring(0, name.length() - 2); // 移除.x后缀
        }
        return name;
    }

    /**
     * 获取所有已加载的插件
     *
     * @return 插件集合
     */
    public Collection<Plugin> getPlugins() {
        return plugins.values();
    }

    /**
     * 根据插件名称获取插件
     *
     * @param pluginName 插件名称
     * @return 插件对象
     */
    public Plugin getPlugin(String pluginName) {
        return plugins.get(pluginName);
    }

    /**
     * 插件类，表示一个已加载的插件
     */
    public static class Plugin {
        private final String name;
        private final File jarFile;
        private final XJarClassLoader classLoader;

        public Plugin(String name, File jarFile, XJarClassLoader classLoader) {
            this.name = name;
            this.jarFile = jarFile;
            this.classLoader = classLoader;
        }

        public String getName() {
            return name;
        }

        public File getJarFile() {
            return jarFile;
        }

        public XJarClassLoader getClassLoader() {
            return classLoader;
        }

        /**
         * 从插件中加载类
         *
         * @param className 类名
         * @return 类对象
         * @throws ClassNotFoundException 类未找到异常
         */
        public Class<?> loadClass(String className) throws ClassNotFoundException {
            return classLoader.loadClass(className);
        }
    }
}